package com.naiterui.ehp.bs.cms.modules.user.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.naiterui.ehp.bs.cms.modules.agent.entity.AgAgent;
import com.naiterui.ehp.bs.cms.modules.agent.entity.AgAgentCustom;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AgAgentCustomMapper;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AgAgentMapper;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.naiterui.ehp.bp.constants.InquirerRelationEnum;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.utils.FileUtil;
import com.naiterui.ehp.bs.cms.common.constants.CacheConstants;
import com.naiterui.ehp.bs.cms.common.entity.BaseTree;
import com.naiterui.ehp.bs.cms.common.exception.BusinessExceptionCode;
import com.naiterui.ehp.bs.cms.common.utils.ConfigUtil;
import com.naiterui.ehp.bs.cms.common.utils.DateUtils;
import com.naiterui.ehp.bs.cms.common.utils.ImageToBase64;
import com.naiterui.ehp.bs.cms.common.utils.OcrUtil;
import com.naiterui.ehp.bs.cms.common.vo.PageParamsVO;
import com.naiterui.ehp.bs.cms.common.vo.PageVO;
import com.naiterui.ehp.bs.cms.modules.common.entity.CmsUserLabel;
import com.naiterui.ehp.bs.cms.modules.common.service.ICmsUserLabelService;
import com.naiterui.ehp.bs.cms.modules.user.bo.record.RecordInfoBO;
import com.naiterui.ehp.bs.cms.modules.user.bo.record.RecordUserInfoBO;
import com.naiterui.ehp.bs.cms.modules.user.bo.record.RecordWorkContractBO;
import com.naiterui.ehp.bs.cms.modules.user.bo.record.ReocrdUserBaseInfoBO;
import com.naiterui.ehp.bs.cms.modules.user.entity.AuditLogs;
import com.naiterui.ehp.bs.cms.modules.user.entity.Doctor;
import com.naiterui.ehp.bs.cms.modules.user.entity.Licence;
import com.naiterui.ehp.bs.cms.modules.user.entity.RecordLog;
import com.naiterui.ehp.bs.cms.modules.user.feign.DoctorFeignClient;
import com.naiterui.ehp.bs.cms.modules.user.mapper.AuditLogsMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.ConsultCommentMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.ConsultComplaintMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.ConsultSessionMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.DepartmentMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.DoctorMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.HospitalMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.LicenceMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.LoginLogMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.PatientPersonDoctorMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.RecordLogMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.RecordUserInfoMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.RecordWorkContractMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.RecordWorkInfoMapper;
import com.naiterui.ehp.bs.cms.modules.user.mapper.StandardDictMapper;
import com.naiterui.ehp.bs.cms.modules.user.service.IDoctorService;
import com.naiterui.ehp.bs.cms.modules.user.vo.AuthAuditLogVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.ConsultCommentVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.ConsultComplaintVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.ConsultSessionVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DepartmentVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DoctorBaseInfoVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DoctorDetailsVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DoctorExpertExcelVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DoctorInfoExcelVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DoctorLicenceVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.DoctorPageVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.HospitalVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.LicenceVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.LoginLogVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.OcrParamVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.StandardDictVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.record.RecordHospitalVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.record.RecordInfoVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.record.RecordUserInfoVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.record.RecordWorkContractVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.record.RecordWorkInfoVO;
import com.naiterui.ehp.bs.cms.modules.user.vo.record.ReocrdUserBaseInfoVO;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class DoctorServiceImpl extends ServiceImpl<DoctorMapper, Doctor> implements IDoctorService {

    private final LicenceMapper licenceMapper;
    private final LoginLogMapper loginLogMapper;
    private final HospitalMapper hospitalMapper;
    private final AuditLogsMapper auditLogsMapper;
    private final RecordLogMapper recordLogMapper;
    private final DepartmentMapper departmentMapper;
    private final ConsultSessionMapper consultSessionMapper;
    private final RecordUserInfoMapper recordUserInfoMapper;
    private final RecordWorkContractMapper recordWorkContractMapper;
    private final RecordWorkInfoMapper recordWorkInfoMapper;
    private final DoctorFeignClient doctorFeignClient;
    private final StandardDictMapper standardDictMapper;
    private final ICmsUserLabelService userLabelService;
    private final ConsultCommentMapper consultCommentMapper;
    private final ConsultComplaintMapper consultComplaintMapper;
    private final PatientPersonDoctorMapper patientPersonDoctorMapper;
    private final AgAgentCustomMapper agAgentCustomMapper;
    private final AgAgentMapper agAgentMapper;

    private static final String[] suffixs = new String[]{"JPG", "PNG"};

    @Value("${ehp.esign-seal-dr-path}")
    private String sealPathPreDr;

    @Value("${ehp.dr-temp-file-path}")
    private String tempFilePath;

    @Value("${ehp.dr-expert-model-path}")
    private String expertModelPath;

    @Value("${file.base.prefix}")
    private String fileBasePrefix;

    @Value("${ehp.domain.img}")
    private String imgHost;

    @Override
    public PageVO<DoctorPageVO> queryPage(PageParamsVO pageParamsVO, DoctorPageVO doctorVO) {

        QueryWrapper<DoctorPageVO> entityWrapper = this.buildEntityWrapper(pageParamsVO, doctorVO);

        Page<DoctorPageVO> page = baseMapper.getPage(pageParamsVO.getPage(), entityWrapper);
        List<DoctorPageVO> doctorPage = page.getRecords();
        doctorPage.forEach(doctorPageVO -> {
            if(StringUtils.isEmpty(doctorPageVO.getHospitalName()) && StringUtils.isNotEmpty(doctorPageVO.getHospitalCustomName())){
                doctorPageVO.setHospitalName(doctorPageVO.getHospitalCustomName());
            }
        });
        page.setRecords(doctorPage);
        return PageVO.toPageVo(page);
    }

    @Override
    public DoctorDetailsVO getDoctorDetailsVO(Long doctorId) {

        //医生资质
        List<Licence> licenceList = licenceMapper.getByDoctorId(doctorId);
        Map<Integer, Licence> licenceMap = licenceList.stream().collect(Collectors.toMap(Licence::getType, e -> e));

        DoctorDetailsVO doctorDetailsVO = new DoctorDetailsVO();

        //基本信息
        DoctorBaseInfoVO doctorBaseInfoVO = baseMapper.getById(doctorId);
        if (doctorBaseInfoVO.getHospitalId() != null && 0 == doctorBaseInfoVO.getHospitalId()) {
            doctorBaseInfoVO.setHospitalName(doctorBaseInfoVO.getHospitalCustomName());
        }
        doctorBaseInfoVO.setEmCard(this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_EMCARD)));
        doctorBaseInfoVO.setMedical(this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_MEDICAL)));
        String sealCertNumber = baseMapper.getSealCertNumberByDoctorId(doctorId);
        doctorBaseInfoVO.setSealCertNumber(sealCertNumber);
        List<AuditLogs> auditLogs = auditLogsMapper.getByDoctorId(doctorId);
        doctorBaseInfoVO.setAuditLogs(auditLogs);
        doctorDetailsVO.setBaseInfo(doctorBaseInfoVO);

        String agentName = "";
        List<AgAgentCustom> dbAgCustomList = agAgentCustomMapper.selectList(Wrappers.lambdaQuery(AgAgentCustom.class).eq(AgAgentCustom::getDoctorId, doctorId));
        if (dbAgCustomList.size() > 0) {
            AgAgent dbAgent = agAgentMapper.selectById(dbAgCustomList.get(0).getAgentId());
            agentName = dbAgent.getName();
        }
        //资质信息
        DoctorLicenceVO doctorLicenceVO = new DoctorLicenceVO();
        BeanUtils.copyProperties(doctorBaseInfoVO, doctorLicenceVO);
        doctorLicenceVO.setIdCard(this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_IDCARD)));
        doctorLicenceVO.setTitleCertificate(this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_TITLECERTIFICATE)));
        doctorLicenceVO.setQualificationCertificate(this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE)));
        List<RecordLog> recordLogList = recordLogMapper.getByDoctorId(doctorId);
        doctorLicenceVO.setRecordLogs(recordLogList);
        doctorLicenceVO.setAgentName(agentName);
        doctorDetailsVO.setLicences(doctorLicenceVO);

        //咨询记录
        List<ConsultSessionVO> consultSessionVOList = consultSessionMapper.getByDoctorId(doctorId);
        consultSessionVOList.stream().forEach(s -> {
            s.setInquirerRelationName(InquirerRelationEnum.getNameByValue(s.getInquirerRelation()));
        });
        doctorDetailsVO.setConsultSessionList(consultSessionVOList);

        //好评率
        Map<Long, String> praiseRateMap = doctorFeignClient.getPraiseRate(Lists.newArrayList(doctorId));
        doctorDetailsVO.setPraiseRate(praiseRateMap.get(doctorId));

        //服务患者数
        doctorDetailsVO.setPatientNum((int) patientPersonDoctorMapper.countByDoctor(doctorId));

        //医生收付服务价格
        Map<Long, Integer> doctorCharge = doctorFeignClient.doctorCharge(doctorId + "", 1);
        doctorDetailsVO.setConsultCharge(doctorCharge.getOrDefault(doctorId, 0));
        Map<Long, Integer> doctorVideoCharge = doctorFeignClient.doctorCharge(doctorId + "", 2);
        doctorDetailsVO.setVideoConsultCharge(doctorVideoCharge.getOrDefault(doctorId, 0));
        List<AuthAuditLogVO> logs = new ArrayList<>();
        auditLogs.stream().forEach(a -> {
            Integer status = a.getStatus();
            String statusDescribe;
            if (status == 1) {
                statusDescribe = "待审核";
            } else if (status == 2) {
                statusDescribe = "已通过";
            } else if (status == 3) {
                statusDescribe = "不通过";
            } else {
                statusDescribe = "未完善";
            }
            logs.add(AuthAuditLogVO.builder()
                    .id(a.getId())
                    .doctorId(a.getDoctorId())
                    .type(1)
                    .status(status)
                    .statusDescribe(statusDescribe)
                    .failureReason(a.getFailureReason())
                    .createdBy(a.getCreatedBy())
                    .createdAt(a.getCreatedAt())
                    .build());
        });
        recordLogList.stream().forEach(r -> {
            Integer status = r.getStatus();
            String statusDescribe;
            if (status == 1) {
                statusDescribe = "备案中";
            } else if (status == 2) {
                statusDescribe = "已备案";
            } else if (status == 3) {
                statusDescribe = "不通过";
            } else {
                statusDescribe = "未备案";
            }
            logs.add(AuthAuditLogVO.builder()
                    .id(r.getId())
                    .doctorId(r.getDoctorId())
                    .type(2)
                    .status(r.getStatus())
                    .statusDescribe(statusDescribe)
                    .failureReason(r.getReason())
                    .createdBy(r.getCreatedBy())
                    .createdAt(r.getCreatedAt())
                    .build());
        });
        if (CollUtil.isNotEmpty(logs)) {
            doctorDetailsVO.setLogs(logs.stream().sorted((a1, a2) -> a2.getCreatedAt().compareTo(a1.getCreatedAt())).collect(Collectors.toList()));
        }
        return doctorDetailsVO;
    }

    private LicenceVO buildLicenceVo(Licence licence) {
        if (licence == null) {
            return null;
        }
        List<String> urls = Splitter.on(',').splitToList(Optional.ofNullable(licence.getUrl()).orElse(""));
        return new LicenceVO(licence.getNumber(), urls);
    }

    private QueryWrapper<DoctorPageVO> buildEntityWrapper(PageParamsVO pageParamsVO, DoctorPageVO doctorPageVO) {
        QueryWrapper<DoctorPageVO> entityWrapper = pageParamsVO.getEntityWrapper("t");
        Long id = doctorPageVO.getId();
        entityWrapper.eq(id != null, "t.id", id);
        Integer status = doctorPageVO.getStatus();
        entityWrapper.eq(status != null, "t.status", status);
        Integer recordStatus = doctorPageVO.getRecordStatus();
        entityWrapper.eq(recordStatus != null, "t.record_status", recordStatus);
        Integer recordPlatformStatus = doctorPageVO.getRecordPlatformStatus();
        entityWrapper.eq(recordPlatformStatus != null, "ru.status", recordPlatformStatus);
        String name = doctorPageVO.getName();
        entityWrapper.like(StringUtils.isNotBlank(name), "t.name", name);
        String phone = doctorPageVO.getPhone();
        entityWrapper.eq(StringUtils.isNotBlank(phone), "t.phone", phone);
        return entityWrapper;
    }

    @Override
    public String uploadSealImg(MultipartFile file, Long doctorId) throws IOException {
        // 生成签名印章
        String extName = FilenameUtils.getExtension(file.getOriginalFilename());
        String filepath = sealPathPreDr + doctorId + "_o." + extName;
        File signImgfile = new File(fileBasePrefix + filepath);
        FileUtils.forceMkdirParent(signImgfile);
        FileUtils.copyInputStreamToFile(file.getInputStream(), signImgfile);

        String imgHost = ConfigUtil.getString("ehp.domain.img");
        return imgHost + filepath;
    }

    @Override
    @Cacheable(value = CacheConstants.HOSPITAL, key = "#cityId")
    public List<HospitalVO> getHospitalByCityId(Long cityId) {
        return hospitalMapper.getByCityId(cityId);
    }

    @Override
    public List<DepartmentVO> getAllDepartment(Long type) {
        List<DepartmentVO> departmentVOS = departmentMapper.finByAll(type);
        // 添加一级部门
        if (!Objects.isNull(type)) {
            DepartmentVO root = new DepartmentVO();
            root.setId(-1L);
            root.setName("顶级部门");
            root.setParentId(-2L);
            departmentVOS.add(root);
        }
        return BaseTree.listToTree(departmentVOS);
    }

    @Override
    @CacheEvict(value = CacheConstants.HOSPITAL, key = "#cityId")
    public void removeHospitalCacheByCityId(Long cityId) {
    }

    @Override
    public RecordInfoVO recordInfo(Long doctorId) {
        RecordInfoVO recordInfoVO = new RecordInfoVO();

        RecordHospitalVO hospitalVO = doctorFeignClient.hospitalInfo();
        recordInfoVO.setHospitalInfo(hospitalVO);

        ReocrdUserBaseInfoVO userBaseInfo = baseMapper.getReocrdUserBaseInfo(doctorId);
        userBaseInfo.setUserType(ReocrdUserBaseInfoVO.USER_TYPE_DR);

        //医生资质
        List<Licence> licenceList = licenceMapper.getByDoctorId(doctorId);
        Map<Integer, Licence> licenceMap = licenceList.stream().collect(Collectors.toMap(Licence::getType, e -> e));

        //医师执业证
        LicenceVO medicalLicenceVO = this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_MEDICAL));
        if (medicalLicenceVO != null) {
            userBaseInfo.setPracNum(medicalLicenceVO.getNumber());
            userBaseInfo.setPracUrls(medicalLicenceVO.getUrls());
        }

        //医师资格证
        LicenceVO qcLicenceVO = this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE));
        if (qcLicenceVO != null) {
            userBaseInfo.setCertNum(qcLicenceVO.getNumber());
            userBaseInfo.setCertUrls(qcLicenceVO.getUrls());
        }

        //身份证
        LicenceVO idCardLicenceVO = this.buildLicenceVo(licenceMap.get(Licence.DOCTOR_LICENCE_TYPE_IDCARD));
        if (idCardLicenceVO != null) {
            userBaseInfo.setIdCardNum(idCardLicenceVO.getNumber());
            userBaseInfo.setIdCardUrls(idCardLicenceVO.getUrls());
        }

        userBaseInfo.setElectronic("/recommend/static/EHP_NTR.PNG");

        recordInfoVO.setUserBaseInfo(userBaseInfo);

        RecordUserInfoVO recordUserInfoVO = recordUserInfoMapper.getByUserId(doctorId, ReocrdUserBaseInfoVO.USER_TYPE_DR);

        if (recordUserInfoVO == null) {
            recordUserInfoVO = new RecordUserInfoVO();
        }
        recordUserInfoVO.setHospitalName(userBaseInfo.getHospitalName());
        recordInfoVO.setUserInfo(recordUserInfoVO);

        List<RecordWorkInfoVO> workInfos = recordWorkInfoMapper.getByUserId(doctorId);
        recordInfoVO.setWorkInfos(workInfos);

        List<RecordWorkContractVO> workContracts = recordWorkContractMapper.getByUserId(doctorId);
        recordInfoVO.setWorkContracts(workContracts);
        return recordInfoVO;
    }

    @Override
    public void updateRecordInfo(RecordInfoVO recordInfoVO) throws BusinessException {
        RecordInfoBO recordInfo = new RecordInfoBO();

        BeanUtils.copyProperties(recordInfoVO, recordInfo);

        ReocrdUserBaseInfoBO userBaseInfo = new ReocrdUserBaseInfoBO();
        BeanUtils.copyProperties(recordInfoVO.getUserBaseInfo(), userBaseInfo);
        recordInfo.setUserBaseInfo(userBaseInfo);

        RecordUserInfoBO userInfo = new RecordUserInfoBO();
        BeanUtils.copyProperties(recordInfoVO.getUserInfo(), userInfo);
        recordInfo.setUserInfo(userInfo);
        List<RecordWorkContractBO> workContracts = recordInfoVO.getWorkContracts()
                .stream()
                .map(recordWorkContractVO -> {
                    RecordWorkContractBO recordWorkContractBO = new RecordWorkContractBO();
                    BeanUtils.copyProperties(recordWorkContractVO, recordWorkContractBO);
                    return recordWorkContractBO;
                }).collect(Collectors.toList());

        recordInfo.setWorkContracts(workContracts);

        doctorFeignClient.updateRecordInfoDr(recordInfo);
    }

    @Override
    public List<StandardDictVO> getStandardDict() {
        return standardDictMapper.getAll();
    }

    @Override
    public String uploadFile(Long doctorId, int type, MultipartFile file) throws IOException {
        String path = this.getLicencePath(doctorId, type);
        String fileName = UUID.randomUUID() + "." + file.getOriginalFilename().split("\\.")[1];
        FileUtils.copyInputStreamToFile(file.getInputStream(), new File(path + fileName));
        return this.getLicenceUrl(doctorId, type, fileName);
    }

    @Override
    public PageVO<DoctorPageVO> findExpertPage(PageParamsVO pageParamsVO, DoctorPageVO doctorVO) {
        QueryWrapper<DoctorPageVO> entityWrapper = this.buildEntityWrapper(pageParamsVO, doctorVO);
        entityWrapper.eq("cul.label_id", CmsUserLabel.LABEL_ID_DOCTOR_EXPERT);
        entityWrapper.eq("cul.user_type", CmsUserLabel.USER_TYPE_DOCTOR);

        Page<DoctorPageVO> page = baseMapper.getExpertPage(pageParamsVO.getPage(), entityWrapper);

        return PageVO.toPageVo(page);
    }

    @Override
    public String importExpert(MultipartFile file) throws BusinessException {
        ImportParams params = new ImportParams();
        List<DoctorExpertExcelVO> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), DoctorExpertExcelVO.class, params);
        } catch (Exception e) {
            throw new BusinessException(BusinessExceptionCode.FILE_IMPORT_ERROR, "文件上传失败， 检查文件格式是否正确");
        }

        //导入数据并生成结果
        for (DoctorExpertExcelVO vo : list) {
            QueryWrapper<Doctor> wrapper = new QueryWrapper<>();
            wrapper.eq("phone", vo.getPhone());
            Doctor doctor = baseMapper.selectOne(wrapper);
            if (doctor == null) {
                vo.setResult("手机号未注册");
            } else if (!doctor.getName().equals(vo.getName())) {
                vo.setResult("信息不匹配");
            } else if (doctor.getStatus() != 2) {
                vo.setResult("未认证通过");
            } else if (doctor.getRecordStatus() != 2) {
                vo.setResult("未备案通过");
            } else if (userLabelService.isDoctorExpert(doctor.getId())) {
                vo.setResult("重复导入");
            } else {
                try {
                    userLabelService.insertDoctorExpert(doctor.getId());
                    vo.setResult("导入成功");
                } catch (Exception e) {
                    vo.setResult("导入异常，请联系管理员");
                    log.error("专家名医导入异常：vo={}, errmsg={}", vo.toString(), e.getMessage());
                }
            }
        }

        //生成导入结果文件
        String resultPath = tempFilePath + "result_" + System.currentTimeMillis() + ".xls";
        log.info("临时导入文件结果地址：resultPath={}", fileBasePrefix + resultPath);
        File resultFile = new File("/" + fileBasePrefix + resultPath);
        try {
            FileUtils.forceMkdirParent(resultFile);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), DoctorExpertExcelVO.class, list);
            workbook.write(byteArrayOutputStream);
            FileUtils.writeByteArrayToFile(resultFile, byteArrayOutputStream.toByteArray());
        } catch (IOException e) {
            throw new BusinessException(BusinessExceptionCode.FILE_IMPORT_ERROR, "导入结果文件写入数据异常");
        }

        return imgHost + resultPath;
    }


    @Override
    public void removeExpert(Long doctorId) {
        userLabelService.removeDoctorExpert(doctorId);
    }

    @Override
    public PageVO<ConsultCommentVO> findCommentByDoctor(Long doctorId, PageParamsVO pageParamsVO) throws BusinessException {
        Page<ConsultCommentVO> page = consultCommentMapper.findByDoctor(pageParamsVO.getPage(), doctorId);
        return PageVO.toPageVo(page);
    }

    @Override
    public PageVO<ConsultComplaintVO> findComplaintByDoctor(Long doctorId, PageParamsVO pageParamsVO) throws BusinessException {
        Page<ConsultComplaintVO> page = consultComplaintMapper.findByDoctor(pageParamsVO.getPage(), doctorId);
        return PageVO.toPageVo(page);
    }

    @Override
    public PageVO<LoginLogVO> appLoginLog(LoginLogVO loginLogParam, PageParamsVO pageParamsVO) {
        QueryWrapper<LoginLogVO> entityWrapper = buildLoginLogWrapper(pageParamsVO, loginLogParam);

        Page<LoginLogVO> page = loginLogMapper.getPage(pageParamsVO.getPage(), entityWrapper);

        return PageVO.toPageVo(page);
    }

    @Override
    public String ocrDistinguish(OcrParamVO ocrParamVO) throws BusinessException {
        String fileUrl = ocrParamVO.getFileUrl();
        if (StringUtils.isBlank(fileUrl)) {
            throw new BusinessException(BusinessExceptionCode.OCR_ERROR, "文件不能为空");
        }
        String str1 = fileUrl.substring(0, fileUrl.indexOf("/doctor/images"));
        String str2 = fileUrl.substring(str1.length());
        File file = new File(fileBasePrefix + str2);
        if (!file.exists()) {
            log.error("下载文件的地址不存在:{}", file.getPath());
            // 如果不存在则抛出异常，由全局异常处理类去处理。
            throw new BusinessException(BusinessExceptionCode.OCR_ERROR, "文件不存在");
        }
        String suffix = FileUtil.getExtensionName(file.getName());
        if (!Arrays.asList(suffixs).contains(suffix.toUpperCase())) {
            throw new BusinessException(BusinessExceptionCode.OCR_ERROR, "不合法的文件类型");
        }
        String base64 = ImageToBase64.file2Base64(file);
        Integer type = ocrParamVO.getType();
        // 识别身份证
        if (type == 1) {
            return OcrUtil.idCardDistinguish(base64);
        }
        // 医师执业证
        else if (type == 2) {
            return OcrUtil.customizeDistinguish(base64);
        }
        // 医师资格证
        return OcrUtil.customizeDistinguish(base64);
    }


    private QueryWrapper<LoginLogVO> buildLoginLogWrapper(PageParamsVO pageParamsVO, LoginLogVO loginLogParam) {
        QueryWrapper<LoginLogVO> entityWrapper = pageParamsVO.getEntityWrapper("t");
        entityWrapper.ge(StringUtils.isNotBlank(pageParamsVO.getDateGte()), "created_at", pageParamsVO.getDateGte());
        if (StringUtils.isNotBlank(pageParamsVO.getDateLte())) {
            if (DateUtils.isNow(pageParamsVO.getDateLte())) {
                Date plus = DateUtils.plus(DateUtils.parseStrToDate(pageParamsVO.getDateLte()), 1, ChronoUnit.DAYS);
                entityWrapper.le("created_at", plus);
            } else {
                entityWrapper.le("created_at", pageParamsVO.getDateLte());
            }
        }
        Long id = loginLogParam.getId();
        entityWrapper.eq(id != null, "t.id", id);
        Integer type = loginLogParam.getType();
        entityWrapper.eq(type != null, "t.type", type);
        String name = loginLogParam.getName();
        entityWrapper.eq(StringUtils.isNotBlank(name), "t.name", name);
        return entityWrapper;
    }

    @Override
    public String modelExpert() {
        return imgHost + expertModelPath;
    }

    private String getLicencePath(Long doctorId, Integer type) {
        Map<Integer, String> licencePathMap = Collections.unmodifiableMap(new HashMap<Integer, String>() {
            private static final long serialVersionUID = 1929740882465317333L;

            {
                this.put(Licence.DOCTOR_LICENCE_TYPE_AVATAR, "/" + fileBasePrefix + "/doctor/images/photo/%d/");
                this.put(Licence.DOCTOR_LICENCE_TYPE_MEDICAL, "/" + fileBasePrefix + "/doctor/images/vocatecer/%d/");
                this.put(Licence.DOCTOR_LICENCE_TYPE_IDCARD, "/" + fileBasePrefix + "/doctor/images/idCard/%d/");
                this.put(Licence.DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE,
                        "/" + fileBasePrefix + "/doctor/images/certificateLicence/%d/");
                this.put(Licence.DOCTOR_LICENCE_TYPE_SIGNATURE, "/" + fileBasePrefix + "/recommend/images/seal/dr/%d/");
                this.put(Licence.DOCTOR_LICENCE_CONTRACT, "/" + fileBasePrefix + "/doctor/images/contract/%d/");
                this.put(Licence.DOCTOR_LICENCE_TYPE_TITLECERTIFICATE, "/" + fileBasePrefix + "/doctor/images/titlecertificate/%d/");
                this.put(Licence.DOCTOR_LICENCE_TYPE_EMCARD, "/" + fileBasePrefix + "/doctor/images/emcard/%d/");
            }
        });
        return String.format(licencePathMap.get(type), doctorId);
    }

    private String getLicenceUrl(Long doctorId, Integer type, String fileName) {
        Map<Integer, String> licenceUrlMap = Collections.unmodifiableMap(new HashMap<Integer, String>() {
            private static final long serialVersionUID = -4656012062992087156L;

            {
                this.put(Licence.DOCTOR_LICENCE_TYPE_AVATAR, imgHost + "/doctor/images/photo/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_TYPE_MEDICAL, imgHost + "/doctor/images/vocatecer/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_TYPE_IDCARD, imgHost + "/doctor/images/idCard/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE, imgHost + "/doctor/images/certificateLicence/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_TYPE_SIGNATURE, imgHost + "/recommend/images/seal/dr/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_CONTRACT, imgHost + "/doctor/images/contract/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_TYPE_TITLECERTIFICATE, imgHost + "/doctor/images/titlecertificate/%d/%s");
                this.put(Licence.DOCTOR_LICENCE_TYPE_EMCARD, imgHost + "/doctor/images/emcard/%d/%s");
            }
        });
        return String.format(licenceUrlMap.get(type), doctorId, fileName);
    }

    @Override
    @CacheEvict(value = CacheConstants.HOSPITAL, allEntries = true, key = "#cityId")
    public void removeHospitalCacheByCityId(Integer cityId) {
    }

    @Override
    public String importExpertDoctor(MultipartFile file) throws BusinessException {
        ImportParams params = new ImportParams();
        List<DoctorInfoExcelVO> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), DoctorInfoExcelVO.class, params);
        } catch (Exception e) {
            throw new BusinessException(BusinessExceptionCode.FILE_IMPORT_ERROR, "文件上传失败， 检查文件格式是否正确");
        }
        if (list.isEmpty()) {
            throw new BusinessException(BusinessExceptionCode.UPLOAD_DATA_IS_EMPTY, "excel数据为空");
        }
        ArrayList<DoctorInfoExcelVO> errorList = new ArrayList<>(); // 手机号、姓名、身份证号码为空存放记录
        ArrayList<DoctorInfoExcelVO> excelList = new ArrayList<>(); // 正常数据

        // 校验正确数据
        for (DoctorInfoExcelVO vo : list) {
            if (StringUtils.isEmpty(vo.getPhone())) {
                vo.setResult("手机号不能为空");
                errorList.add(vo);
            } else if (StringUtils.isEmpty(vo.getName())) {
                vo.setResult("姓名不能为空");
                errorList.add(vo);
            } else if (StringUtils.isEmpty(vo.getIdCard())) {
                vo.setResult("身份证号码不能为空");
                errorList.add(vo);
            } else {
                excelList.add(vo);
            }
        }
        try {
            doctorFeignClient.batchSaveDoctor(excelList);
        } catch (Exception e) {
            log.error("医生数据导入异常：vo={}, errmsg={}", e.getMessage());
            throw new BusinessException(BusinessExceptionCode.FILE_IMPORT_ERROR, "导入异常");

        }

        // 生成导入结果文件
        String resultPath = tempFilePath + "result_" + System.currentTimeMillis() + ".xls";
        log.info("临时导入文件结果地址：resultPath={}", fileBasePrefix + resultPath);
        File resultFile = new File("/" + fileBasePrefix + resultPath);
        try {
            FileUtils.forceMkdirParent(resultFile);
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), DoctorInfoExcelVO.class, errorList);
            workbook.write(byteArrayOutputStream);
            FileUtils.writeByteArrayToFile(resultFile, byteArrayOutputStream.toByteArray());
        } catch (IOException e) {
            throw new BusinessException(BusinessExceptionCode.FILE_IMPORT_ERROR, "导入结果文件写入数据异常");
        }

        return imgHost + resultPath;
    }

}
